package left42dead;

import java.util.HashMap;

/**
 * This class collects and provides some statistical data on the state of a
 * field. It is flexible: it will create and maintain a counter for any class of
 * object that is found within the field.
 * 
 * @author David J. Barnes and Michael Kolling
 * @version 2008.03.30
 */
public class FieldStats
{
    // Counters for each type of entity (human, vampire, etc.) in the simulation.
    private HashMap<Class, Counter> counters;
    // Whether the counters are currently up to date.
    private boolean countsValid;

    /**
     * Construct a FieldStats object.
     */
    public FieldStats ()
    {
        // Set up a collection for counters for each type of animal that
        // we might find
        counters = new HashMap<Class, Counter>();
        countsValid = true;
    }

    /**
     * Get details of what is in the field.
     * 
     * @return A string describing what is in the field.
     */
    public String getPopulationDetails (Field field)
    {
        StringBuffer buffer = new StringBuffer();
        
        if (!countsValid)
            generateCounts(field);
        
        for (Class key : counters.keySet())
        {
            Counter info = counters.get(key);

            // Format class name
            String[] classNames = info.getName().split("\\.");
            String className = (classNames.length > 0 ?
                    classNames[classNames.length - 1] :
                    "");

            buffer.append(className);
            buffer.append(": ");
            buffer.append(info.getCount());
            buffer.append(' ');
        }
        
        return buffer.toString();
    }

    /**
     * Invalidate the current set of statistics; reset all counts to zero.
     */
    public void reset ()
    {
        countsValid = false;
        for (Class key : counters.keySet())
        {
            Counter count = counters.get(key);
            count.reset();
        }
    }

    /**
     * Increment the count for one class
     * 
     * @param targetClass The class to increment.
     */
    public void incrementCount (Class targetClass)
    {
        Counter count = counters.get(targetClass);
        if (count == null)
        {
            // We do not have a counter for this species yet.
            // Create one.
            count = new Counter(targetClass.getName());
            counters.put(targetClass, count);
        }
        count.increment();
    }

    /**
     * Indicate that a class count has been completed.
     */
    public void countFinished ()
    {
        countsValid = true;
    }

    /**
     * Determine whether the simulation is still viable. I.e., should it
     * continue to run.
     * 
     * @return true If there is more than one species alive.
     */
    public boolean isViable (Field field)
    {
        // How many counts are non-zero.
        int nonZero = 0;
        if (!countsValid)
        {
            generateCounts(field);
        }
        for (Class key : counters.keySet())
        {
            Counter info = counters.get(key);
            if (info.getCount() > 0)
            {
                nonZero++;
            }
        }
        return nonZero > 1;
    }

    /**
     * Generate counts of the number of each classes. These are not kept up
     * to date as classes are placed in the field, but only when a
     * request is made for the information.
     * 
     * @param field The field to generate the stats for.
     */
    private void generateCounts (Field field)
    {
        reset();
        for (int row = 0; row < field.getDepth(); row++)
        {
            for (int col = 0; col < field.getWidth(); col++)
            {
                Object obj = field.getObjectAt(row, col);
                if (obj != null)
                {
                    incrementCount(obj.getClass());
                }
            }
        }
        countsValid = true;
    }
}
